﻿#include "../x/eventTranslate.h"
#include "../control.h"
#include <cstdio>

namespace swui
{
	class ctlRoot;
	extern void _draw_caret(_ctlInterior::drawInfo*, _ctlInterior::caret*, ctlRoot*);
	namespace _ctlInterior
	{
		eventTranslator& eventTranslator::getControlEventTrans(ctlRoot* root)
		{
			return root->_eventTrans;
		}
		void eventTranslator::setParent(ctlRoot* rot)
		{
			std::lock_guard<decltype(child_mutex)> gurad(child_mutex);
			if(rot->getRoot() == relation->getRoot()
				&& relation->getParent())
			{
				relation->getParent()->_eventTrans.pop(relation);
				rot->_eventTrans.push(relation);
			}
		}
		bool eventTranslator::isZOrderTop(ctlRoot* r)
		{
			std::lock_guard<decltype(child_mutex)> gurad(child_mutex);
			return std::find(zord_top.begin(), zord_top.end(), r) != zord_top.end();
		}
		void eventTranslator::setZOrderTop(ctlRoot* r)
		{
			std::lock_guard<decltype(child_mutex)> gurad(child_mutex);
			if(std::find(zord_top.begin(), zord_top.end(), r) == zord_top.end())
				zord_top.push_back(r);
		}
		void eventTranslator::moveTo(unsigned pos)
		{
			std::lock_guard<decltype(child_mutex)> gurad(child_mutex);
			auto& cds = relation->getParent()->_eventTrans.childControls;
			auto iter = std::find(cds.begin(), cds.end(), relation);
			cds.erase(iter);
			cds.insert(cds.begin() + pos, relation);
			auto& zord = relation->getParent()->_eventTrans.zord_top;
			auto iter2 = std::find(zord.begin(), zord.end(), relation);
			if(iter2 != zord.end() && pos < cds.size() - zord.size())
				zord.erase(iter2);
		}
		void eventTranslator::setCursor(std::wstring::const_pointer name)
		{
			getMajorInfo()->hCursor = LoadCursorW(0, name);
			getMajorInfo()->bindCursor = true;
		}
		void eventTranslator::releaseCursor()
		{
			getMajorInfo()->bindCursor = false;
		}
		void CALLBACK timercallback(HWND hWnd, UINT, UINT id, DWORD)
		{
			std::function<bool()>* fun = (std::function<bool()>*)id;
			if((*fun)() == false)
			{
				KillTimer(hWnd, id);
				delete fun;
			}
		}
		unsigned eventTranslator::setTimer(unsigned time, std::function<bool()> fun)
		{
			auto func = new std::function<bool()>(fun);
			SetTimer(getMajorInfo()->hWnd, (unsigned)func, time, timercallback);
			return (unsigned)func;
		}
		void eventTranslator::killTimer(unsigned id)
		{
			if(KillTimer(getMajorInfo()->hWnd, id) != 0)
				delete (std::function<bool()>*)id;
		}
		ctlRect eventTranslator::getParentRect()
		{
			ctlRoot* parent = relation->getParent();
			if(parent == 0)
			{
				RECT client;
				GetClientRect(getMajorInfo()->hWnd, &client);
				return ctlRect(client.left, client.top, 
					client.right - client.left, client.bottom - client.top);
			}
			return parent->getRect();
		}
		void eventTranslator::relateParent(ctlRoot* parent)
		{
			topest = parent->_eventTrans.topest;
			mInfo = parent->_eventTrans.mInfo;
		}
		void eventTranslator::setCapture()
		{
			if(getMajorInfo()->mouseCapture == 0) 
				SetCapture(getMajorInfo()->hWnd);
			getMajorInfo()->mouseCapture = relation;
		}
		void eventTranslator::releaseCapture()
		{
			getMajorInfo()->mouseCapture = 0;
			ReleaseCapture();
		}
		void eventTranslator::draw(drawInfo* info)
		{
			if(!relation->isShow()) return;
			std::lock_guard<decltype(child_mutex)> gurad(child_mutex);
			unsigned number = relation->_get_redraw_or_event_number();
			for(unsigned count = 0; count != number; ++count)
			{
				containType::const_pointer beg = relation->_get_redraw_begin(count);
				for(unsigned end = relation->_get_redraw_end(count), j = 0; j != end; ++beg, ++j)
				{
					if(!(*beg)->isShow()) continue;
					ctlRect absRect = (*beg)->getAbsoluteRect();
					RECT thisRect;
					SetRect(&thisRect, absRect.getLeft(), absRect.getTop(),
						absRect.getRight(), absRect.getBottom());
					if(RectInRegion(info->drawRegion, &thisRect) == 0) 
						continue;
					//设置裁剪矩形
					HRGN hRgn = CreateRectRgnIndirect(&thisRect);
					CombineRgn(hRgn, hRgn, info->drawRegion, RGN_AND);
					SelectClipRgn(info->hDC, hRgn);
					//保存视口原点防止绘制时被改变
					POINT tempViewportPt;
					GetViewportOrgEx(info->hDC, &tempViewportPt);
					//绘制当前控件
					(*beg)->_alpha_redraw_(info);
					//恢复绘制之前的视口原点
					POINT viewport2;
					GetViewportOrgEx(info->hDC, &viewport2);
					if(tempViewportPt.x != viewport2.x || tempViewportPt.y != viewport2.y)
					{
						SetViewportOrgEx(info->hDC, tempViewportPt.x, tempViewportPt.y, NULL);
						relation->redrawAllControl();
					}
					if(getMajorInfo()->hCaret.getLevel() == *beg)
						_draw_caret(info, &getMajorInfo()->hCaret, *beg);
					if(!(*beg)->_eventTrans.empty())
					{
						//不是最下级控件，交给下级控件绘制
						drawInfo nextInfo(*info);
						if((*beg)->_combine_child_rgn(hRgn))
							SelectClipRgn(nextInfo.hDC, hRgn);
						nextInfo.drawRegion = hRgn;
						//事件下发
						POINT oldPoint;
						SetViewportOrgEx(nextInfo.hDC, absRect.getLeft(), absRect.getTop(), &oldPoint);
						(*beg)->_eventTrans.draw(&nextInfo);
						SetViewportOrgEx(nextInfo.hDC, oldPoint.x, oldPoint.y, NULL);
					}
					//恢复裁剪矩形
					SelectClipRgn(info->hDC, info->drawRegion);
					DeleteObject(hRgn);
				}
			}
		}
		bool eventTranslator::vicMouse(ctlMouseEvent& me, ctlRoot* ctl, bool check)
		{
			ctlNotifyEvent ne;
			ne.eventType = ctlNotifyEventType::hittest;
			ctlNotifyHittest nh;
			ne.info = &nh;
			bool _is_in_control = false;
			nh.isInControl = &_is_in_control;
			nh.mousePos = me.mousePos;
			nh.mousePos.x -= relation->getLeft();
			nh.mousePos.y -= relation->getTop();
			nh.absolutePos = me.absolutePos;
			relation->_notify_event_(&ne);
			if(!check || ctl->_judge_point_(me.mousePos) || _is_in_control)
			{
				if(check)
				{
					me.mousePos.x -= ctl->getLeft();
					me.mousePos.y -= ctl->getTop();
				}

				//如果是最下层的控件
				if(!check || !ctl->_eventTrans.mouse(&me))
				{
					switch(me.eventType)
					{
					case ctlMouseEventType::leftDBClick:
					case ctlMouseEventType::rightDBClick:
						me.eventFrom = ctl->getParent();
						ctl->_mouse_event_(&me);
						break;
					case ctlMouseEventType::leftDown:
					case ctlMouseEventType::rightDown:
						ctl->_eventTrans.setCapture();
						me.eventFrom = ctl->getParent();
						ctl->_mouse_event_(&me);
						ctl->redraw();
						break;
					case ctlMouseEventType::leftUp:
					case ctlMouseEventType::rightUp:
						ctl->_eventTrans.releaseCapture();
						if(getMajorInfo()->mouseStay == ctl)
						{
							ctlMouseEvent pressme = me;
							switch(me.eventType)
							{
							case ctlMouseEventType::leftUp:
								pressme.eventType = ctlMouseEventType::leftPress; break;
							case ctlMouseEventType::rightUp:
								pressme.eventType = ctlMouseEventType::rightPress; break;
							}
							pressme.eventFrom = ctl->getParent();
							ctl->_mouse_event_(&pressme);
						}
						me.eventFrom = ctl->getParent();
						ctl->_mouse_event_(&me);
						ctl->redraw();
						break;
					case ctlMouseEventType::move:
						ctlRoot* mouseStay = getMajorInfo()->mouseStay;
						getMajorInfo()->mouseStay = ctl;
						if(mouseStay != ctl && mouseStay != 0)
						{	//leave 和 enter消息
							ctlMouseEvent leaveme = me;
							leaveme.eventType = ctlMouseEventType::leave;
							leaveme.mousePos = mouseStay->_eventTrans.pointTrans(
								leaveme.mousePos, ctl);
							leaveme.eventFrom = mouseStay->getParent();
							mouseStay->_mouse_event_(&leaveme);
							mouseStay->redraw();
							ctlMouseEvent enterme = me;
							enterme.eventType = ctlMouseEventType::enter;
							enterme.eventFrom = ctl->getParent();
							ctl->_mouse_event_(&enterme);
							ctl->redraw();
						}
						me.eventFrom = ctl->getParent();
						ctl->_mouse_event_(&me);
						break;
					}
				}
				return true;
			}
			return false;
		}
		bool eventTranslator::mouse(ctlMouseEvent* info)
		{
			if(!relation->isVisible()) return false;
			ctlMouseEvent me = *info;
			std::lock_guard<decltype(child_mutex)> gurad(child_mutex);
			for(unsigned count = 0; count != relation->_get_redraw_or_event_number(); ++count)
			{
				containType::const_pointer beg = relation->_get_event_begin(count);	
				for(unsigned end = relation->_get_event_end(count), i = 0; i != end; --beg, ++i)
				{	//发送事件到子控件
					if(!(*beg)->isShow() || !(*beg)->isEnabled()) continue;
					if(vicMouse(me, *beg))
						return true;	//如果检测到最下级子控件就返回
				}
			}
			//检测不到下级就表示当前为最下级		[无需再次检测鼠标是否在当前控件]
			return vicMouse(me, relation, false);
		}
		ctlPoint eventTranslator::pointTrans(ctlPoint pt, ctlRoot* from)
		{
			ctlRoot* pre = from;
			while(pre)
			{
				pt.x += pre->getLeft();
				pt.y += pre->getTop();
				pre = pre->getParent();
			}
			ctlRoot* suf = relation;
			while(suf)
			{
				pt.x -= suf->getLeft();
				pt.y -= suf->getTop();
				suf = suf->getParent();
			}
			return pt;
		}
		void eventTranslator::killFocus()
		{
			ctlRoot* prefocus = getMajorInfo()->focus;
			if(prefocus != nullptr)
			{
				if(getMajorInfo()->hCaret.getLevel() == prefocus)
				{
					getMajorInfo()->hCaret.setLevel(nullptr);
					getMajorInfo()->hCaret.setStatus(false);
					prefocus->redraw();
				}
				getMajorInfo()->preFocus = prefocus;
				getMajorInfo()->focus = nullptr;
				ctlNotifyEvent ne;
				ne.info = nullptr;
				ne.eventType = ctlNotifyEventType::blur;
				prefocus->_notify_event_(&ne);
			}
		}
		void eventTranslator::setFocus()
		{
			if(getMajorInfo()->focus == relation)
				return;
			killFocus();
			getMajorInfo()->focus = relation;
			ctlNotifyEvent ne;
			ne.info = nullptr;
			ne.eventType = ctlNotifyEventType::focus;
			relation->_notify_event_(&ne);
		}
	}   //namespace _ctlInterior
}	//namespace swui
